/*
 * Copyright 2014-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.codecentric.boot.admin.client.registration;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;

import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
public class IpUtil {
	private static final Logger log = LoggerFactory.getLogger(IpUtil.class);

	/**
	 * 获取用户真实IP地址，不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,
	 * 如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个,而是一串IP值,取X-Forwarded-For中第一个非unknown的有效IP字符串即可。
	 * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100 用户真实IP为：
	 * 192.168.1.110
	 * <p>
	 * <p>
	 * location = /freightByIp{
	 * proxy_pass http://xdx8082.com;
	 * proxy_redirect    off;
	 * proxy_set_header  Host             $host;
	 * proxy_set_header  X-Real-IP        $remote_addr;
	 * proxy_set_header  X-Forwarded-For  $proxy_add_x_forwarded_for;
	 * }
	 *
	 * @param request request对象
	 * @return String
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}


	/**
	 * 获取主机名
	 *
	 * @return 本地主机名
	 */
	public static String getHostName() {
		try {
			return InetAddress.getLocalHost().getHostName();
		} catch (UnknownHostException e) {
		}
		return "未知";
	}


	/**
	 * 获取服务ip
	 *
	 * @return
	 */
	public static String getIp() {
		return ip;
	}

	/*默认给个广播*/
	private static String ip = "0.0.0.0";
	private static String[] displayNameArr = {"VMware", "Hyper-V", "Cisco", "Sangfor", "VirtualBox", "virbr", "docker", "flannel", "cali", "br-", "veth", "ZeroTier", "tun0", "tap0"};

	/**
	 *         windows环境可以使用下面的方式获取，但是无法排除虚拟网卡
	 *
	 *         String osName = System.getProperty("os.name");
	 *         if (osName.toLowerCase().indexOf("windows") > -1) {
	 *             try {
	 *                 InetAddress i = InetAddress.getLocalHost();
	 *                 ip = i.getHostAddress();
	 *                 log.info("windows环境-slf4j获取ip=" + ip);
	 *             } catch (UnknownHostException e) {
	 *                 log.error("windows环境-slf4j获取ip异常", e);
	 *             }
	 *         }
	 */
	static {
		try {
			boolean bFindIP = false;
			InetAddress ia = null;
			Enumeration<NetworkInterface> netInterfaces = NetworkInterface.getNetworkInterfaces();
			while (netInterfaces.hasMoreElements()) {
				if (bFindIP) {
					break;
				}

				NetworkInterface ni = netInterfaces.nextElement();

				//判断是否为虚拟网卡
				String displayName = ni.getDisplayName();
				boolean isVirtualDevice = false;
				for (String displayNameKeyword : displayNameArr) {
					if (displayName.contains(displayNameKeyword)) {
						isVirtualDevice = true;
						break;//中断这一层for循环
					}
				}

				//跳过虚拟网卡
				if (isVirtualDevice) {
					continue;
				}

				Enumeration<InetAddress> ips = ni.getInetAddresses();
				while (ips.hasMoreElements()) {
					ia = ips.nextElement();
					if (ia.isSiteLocalAddress() && !ia.isLoopbackAddress() && ia.getHostAddress().indexOf(":") == -1) {
						bFindIP = true;
						break;
					}
				}
			}
			if (null != ia) {
				ip = ia.getHostAddress();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		/**
		 * 新版本springboot启动时无法使用sl4j输出日志(老版本可以),因此这里只能使用System.out.println(msg);
		 */
		String msg = String.format("sl4j获取ip=%s,osName=%s", ip, System.getProperty("os.name"));
		System.out.println(msg);
	}
}
